# Kestrel: An XMPP-based Many-Task Computing Scheduler
# Author: Lance Stout <lancestout@gmail.com>
#
# Copyright 2009-2010 Clemson University
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import sleekxmpp

from kestrel.core.xmpp import Base


class Client(Base):
    """
    A client XMPP module. Using this module should typically
    be done only for testing or small applications due to XMPP
    client scalability issues. For applications requiring
    thousands of entries in their roster, use an XMPP server
    component instead.

    Configuration entries for this module:
      XMPP/client/username
      XMPP/client/password
      XMPP/client/server
      XMPP/type

    Events listened for by this module:
      system/start
      system/shutdown
      message/send
      presence/send

    Events raised by this module:
      system/available
      system/online
      system/offline
      message
      presence/available
      presence/busy
      presence/offline
      presence/subscribe
      presence/subscribed
      presence/unsubscribe
      presence/unsubscribed
    """

    def __init__(self, kernel):
        """
        Instantiate an XMPP client module that will connect
        to the given server using the username and password
        as credentials.
        """
        self.xmpp = None
        self.kernel = kernel

        username = kernel.config('XMPP/client/username')
        self.server = kernel.config('XMPP/client/server')
        self.password = kernel.config('XMPP/client/password')
        self.jid = username + '@' + self.server
        self.has_roster = True

        self.events = {'system/start': self.connect,
                       'system/shutdown': self.disconnect,
                       'message/send': self.send_message,
                       'presence/send': self.send_status}

        self.kernel.register(self)

    def connect(self, data=None):
        """
        Start the XMPP module and establish a connection with the server.
        """
        self.kernel.set_config('XMPP/type', 'client')

        self.xmpp = sleekxmpp.ClientXMPP(self.jid, self.password)

        # Since the SleekXMPP library also uses an event engine, we
        # must provide event handlers to it which will in turn raise
        # events for our kernel to process.
        self.xmpp.add_event_handler("session_start", self.on_start)
        self.xmpp.add_event_handler("message", self.recv_message,
                                    threaded=True)
        self.xmpp.add_event_handler("got_online", self.recv_status)
        self.xmpp.add_event_handler("got_offline", self.recv_status)
        self.xmpp.add_event_handler("changed_status", self.recv_status)
        self.xmpp.add_event_handler("changed_subscription", self.change_roster)
        # SleekXMPP by default authorizes and subscribes to any subscription
        # request. Overriding these settings is needed in order to make
        # subscription behaviour configurable through application policy.
        self.xmpp.auto_authorize = None
        self.xmpp.auto_subscribe = False

        if self.xmpp.connect((self.server, 5222)):
            self.xmpp.process(threaded=False)
        else:
            self.kernel.log("ERROR", "Could not establish XMPP connection.")
